# -*- coding: utf-8 -*-
'''
@文件    :user.py
@说明    :
@时间    :2025/08/28 15:30:00
@作者    :浪晋
@版本    :1.0
'''
from datetime import datetime, timedelta
from typing import Optional, Tuple, List, Dict
from tortoise.expressions import Q
from fastapi.exceptions import HTTPException
from app.cruds.system.user import crud, Total
from app.cruds.system.role import crud as role_crud
from app.cruds.system.dept import crud as dept_crud
from app.schemas.base import LoginPasswordForm
from app.schemas.system.user import QuerySchema, CreateSchema, UpdateSchema
from app.enums.settings import DataFilterTypeEnum, LoginTypeEnum
from app.core.plugin import password, redis, jwt
from app.utils.buildDataFunc import build_tree_data
from app.settings.config import config

class Service:
    async def list(self, payload: QuerySchema) -> Tuple[Total, List[Dict]]:
        search = Q(superuser=False)
        if payload.realname:
            search &= Q(realname__icontains=payload.realname)
        if payload.nickname:
            search &= Q(nickname__icontains=payload.nickname)
        if payload.account:
            search &= Q(account__icontains=payload.account)
        if payload.active is not None:
            search &= Q(active=payload.active)
        if payload.dept_id:
            search &= Q(dept_id=payload.dept_id)
        order = []
        if payload.order:
            order.append(payload.order)
        total, objs = await crud.list(page_num=payload.pageNum, page_size=payload.pageSize, search=search, order=order)
        result = []
        for obj in objs:
            item = obj.to_dict(exclude=['password','superuser'])
            item['dept'] = obj.dept.to_dict(exclude=['path', 'active', 'parent_id', 'create_time', 'update_time', 'desc', 'order'])
            item['roles'] = [{'id':role.id,'name':role.name} for role in obj.roles]
            result.append(item)
        return total, result

    async def create(self, data: CreateSchema) -> Dict:
        search = Q(account=data.account) | Q(phone=data.phone)
        obj = await crud.query(search)
        if obj:
            raise HTTPException(status_code=200, detail="账号或手机已被注册")
        data.password = password.get_password_hash(data.password)
        data_dict = data.model_dump(exclude={'roles'})
        data_dict['dept'] = await dept_crud.get(data.dept)
        obj = await crud.create(data_dict)
        roles = [await role_crud.get(role_id) for role_id in data.roles]
        obj = await crud.save_user_roles(obj, roles)
        return obj.to_dict()

    async def update(self, data: UpdateSchema) -> Optional[Dict]:
        obj = await crud.get_by_id(data.id)
        if not obj:
            raise HTTPException(status_code=200, detail="数据不存在")
        data_dict = data.model_dump(exclude={'id','roles'})
        data_dict['dept'] = await dept_crud.get(data.dept)
        obj =  await crud.update(obj, data_dict)
        roles = [await role_crud.get(role_id) for role_id in data.roles]
        obj = await crud.save_user_roles(obj, roles)
        return obj.to_dict()

    async def active(self, id: int) -> Optional[Dict]:
        obj = await crud.get_by_id(id)
        if not obj:
            raise HTTPException(status_code=200, detail="数据不存在")
        obj = await crud.update(obj, {
            "active": not obj.active
        })
        return obj.to_dict()
    
    async def delete(self, id: int):
        obj = await crud.get_by_id(id)
        if not obj:
            raise HTTPException(status_code=200, detail="数据不存在")
        await crud.delete(obj)

    async def init_user_data(self):
        """初始化菜单数据"""
        count = await crud.count()
        if count == 0:
            from app.mock.data import users
            for item in users:
                await crud.create(item)

    async def authenticate_password(self, data: LoginPasswordForm) -> Dict:
        obj = await crud.get_by_account(data.username)
        if not obj:
            raise HTTPException(status_code=200, detail="账号不存在")
        if not password.verify_password(data.password, obj.password):
            raise HTTPException(status_code=200, detail="密码错误")
        if  not obj.active:
            raise HTTPException(status_code=200, detail="账号未激活")
        obj = await crud.update(obj,{
            "last_login_time": datetime.now(),
            "last_login_ip": data.client_ip,
            "last_login_type": LoginTypeEnum.PASSWORD
        })
        payload = {
            "id": obj.id,
            "account": obj.account,
            "nickname": obj.nickname,
            "last_login_time": obj.last_login_time.strftime("%Y-%m-%d %H:%M:%S"),
            "last_login_ip": obj.last_login_ip,
            "last_login_type": obj.last_login_type,
            "permission": obj.permission,
            "superuser": obj.superuser,
            "exp": datetime.now() + timedelta(seconds=config.EXPIRE_TIME),
        }
        token = jwt.generate_token(payload)
        await redis.set(f"{config.REDIS_PREFIX_NAME}:admin:{obj.account}", token, config.EXPIRE_TIME)
        result = {
            "token": token,
            "expires": config.EXPIRE_TIME,
            "info": {
                "realname": obj.realname,
                "nickname": obj.nickname,
                "avatar": obj.avatar
            }
        }
        return result

    async def get_user_menus(self, id: int) -> Dict:
        obj = await crud.get_by_id(id)
        if not obj:
            raise HTTPException(status_code=200, detail="数据不存在")
        menus = []
        for role in await obj.roles:
            menu = await role.menus
            menus.extend(menu)
        menus = list(set(menus))
        result = []
        permissions = []
        for menu in menus:
            if menu.type == "button":
                permissions.append(menu.name)
            result.append({
                "id":menu.id,
                "name":menu.name,
                "path":menu.path,
                "component":menu.component,
                "parent_id":menu.parent_id,
                "meta":{
                    "icon": menu.icon,
                    "title": menu.title,
                    "hidden": menu.hidden,
                    "hiddenBreadcrumb": menu.hiddenBreadcrumb,
                    "type": menu.type,
                    "fullpage": menu.fullpage
                }
            })
        data = {
            "menus": build_tree_data(result),
            "permissions":permissions,
            "dashboardGrid":['statistics','welcome','echarts','about', 'ver','time','progress']
        }
        return data



service = Service()